package com.zhihaoliang.coroutine.buss.flow.func

import com.zhihaoliang.coroutine.util.log
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*

/**
 * @author 支豪亮
 * @date 2022/10/25 17:34
 * @des Flattening flows:flatMapConcat、flatMapMerge、flatMapLatest 展平流
 */
object FlowFlatten {

    @OptIn(FlowPreview::class)
    fun onFlatMapConcat(mainScope: CoroutineScope) = mainScope.launch {
        var startTime = System.currentTimeMillis() // remember the start time
        var useTime = System.currentTimeMillis()
        (1..3).asFlow().onEach { delay(100) } // emit a number every 100 ms
            .flatMapConcat { requestFlow(it) }
            .collect { value -> // collect and print
                log("start ： $value: ${System.currentTimeMillis() - startTime} : ${System.currentTimeMillis() - useTime}")
                useTime = System.currentTimeMillis()
            }

         startTime = System.currentTimeMillis() // remember the start time
         useTime = System.currentTimeMillis()
        (1..3).asFlow().onEach { delay(600) } // emit a number every 100 ms
            .flatMapConcat { requestFlow(it) }
            .collect { value -> // collect and print
                log("end ： $value: ${System.currentTimeMillis() - startTime} : ${System.currentTimeMillis() - useTime}")
                useTime = System.currentTimeMillis()
            }
    }

    @OptIn(FlowPreview::class)
    fun onFlatMapMerge(mainScope: CoroutineScope) = mainScope.launch {
        var startTime = System.currentTimeMillis() // remember the start time
        var useTime = System.currentTimeMillis()
        (1..3).asFlow().onEach { delay(800) } // emit a number every 100 ms
            .flatMapMerge { requestFlow(it) }
            .collect { value -> // collect and print
                log("start ： $value: ${System.currentTimeMillis() - startTime} : ${System.currentTimeMillis() - useTime}")
                useTime = System.currentTimeMillis()
            }

         startTime = System.currentTimeMillis() // remember the start time
         useTime = System.currentTimeMillis()
        (1..3).asFlow().onEach { delay(100) } // emit a number every 100 ms
            .flatMapMerge { requestFlow(it) }
            .collect { value -> // collect and print
                log("end ： $value: ${System.currentTimeMillis() - startTime} : ${System.currentTimeMillis() - useTime}")
                useTime = System.currentTimeMillis()
            }
    }

    @OptIn(ExperimentalCoroutinesApi::class)
    fun onFlatMapLatest(mainScope: CoroutineScope) = mainScope.launch {
        var startTime = System.currentTimeMillis() // remember the start time
        var useTime = System.currentTimeMillis()
        (1..3).asFlow().onEach { delay(800) } // emit a number every 100 ms
            .flatMapLatest { requestFlow(it) }
            .collect { value -> // collect and print
                log("start ： $value: ${System.currentTimeMillis() - startTime} : ${System.currentTimeMillis() - useTime}")
                useTime = System.currentTimeMillis()
            }

        startTime = System.currentTimeMillis() // remember the start time
        useTime = System.currentTimeMillis()
        (1..3).asFlow().onEach { delay(100) } // emit a number every 100 ms
            .flatMapLatest { requestFlow(it) }
            .collect { value -> // collect and print
                log("end ： $value: ${System.currentTimeMillis() - startTime} : ${System.currentTimeMillis() - useTime}")
                useTime = System.currentTimeMillis()
            }
    }


    private fun requestFlow(i: Int): Flow<String> = flow {
        emit("$i: First")
        delay(500) // wait 500 ms
        emit("$i: Second")
        delay(500) // wait 500 ms
        emit("$i: Third")
    }
}